#include "util.h"

#ifndef __INTEGERARRAY_H_
#define __INTEGERARRAY_H_

// An array of unsigned integers 
// Each integer has a fixed number of bits

inline string BitsToString(uint64 n) {
  string s;
  for (uint64 i=0; i<64; i++) s += ((n >> (63-i)) & 1) ? '1' : '0';
  return s; }

struct IntegerArray {
IntegerArray() :data_(NULL), data_owned_(false) { }
  ~IntegerArray() { if (data_owned_) delete [] data_; }

  // integer_size is in bits.  Must be <=64
  void Init(uint64 num_integers, uint64 integer_size);
  void Load(Memblock m);
  void Write(ostream *output);
  uint64 size() { return num_integers_; }
  static void ConvertAndStream(ostream *output, 
			       uint64 *data, 
			       uint64 num_integers, 
			       uint64 integer_size);
  uint64 Get(uint64 i);
  void Set(uint64 i, uint64 val);

  uint64 integer_size_; // number of bits per integer
  uint64 num_integers_;   // number of elements
  uint64 word_size_; // size of data
  uint64 * data_; // where the actual data is stored 
  bool data_owned_;

  struct Reference {
    IntegerArray *a_;
    uint64 pos_;
    Reference() {}
  Reference(const Reference &o) :a_(o.a_), pos_(o.pos_) { CHECK(false);}
  Reference(IntegerArray *a, uint64 pos) :a_(a), pos_(pos) {}
    Reference & operator = (uint64 val) { 
      a_->Set(pos_, val); return *this; 
    }
      uint64 Get() const {
	uint64 ret = a_->Get(pos_);
	return ret;
      }
    operator uint64 () const { return Get(); }
    Reference &operator= (const Reference & o) {
      // CHECK(false);
      a_->Set(pos_, o.Get());
      return *this;
    }
  };
  struct iterator {
    typedef random_access_iterator_tag iterator_category;
    typedef uint64 value_type;
    typedef uint64 difference_type;
    typedef iterator pointer;
    typedef Reference reference;

    IntegerArray *a_;
    uint64 pos_;
    Reference operator *() { Reference r;
      r.a_ = a_;
      r.pos_ = pos_;
      return r; }
    iterator & operator++ () { pos_++; return *this; }
    iterator & operator-- () { pos_--; return *this; }
    iterator operator++(int) { iterator ret = *this; pos_++; return ret; }
    iterator operator--(int) { iterator ret = *this; pos_--; return ret; }
    void operator +=(uint64 i) {pos_ += i;}
    void operator -=(uint64 i) {pos_ -= i;}
    iterator operator +(int64 i) {
      iterator ret = *this; ret.pos_ += i; return ret; }
    iterator operator -(int64 i) {
      iterator ret = *this; ret.pos_ -= i; return ret; }
    bool operator !=(const iterator &o) { return (pos_ != o.pos_); }
    bool operator ==(const iterator &o) { return (pos_ == o.pos_); }
    bool operator <(const iterator &o) { return (pos_ < o.pos_); }
    int64 operator -(const iterator &o) { return (pos_ - o.pos_); }
   
  };
  iterator begin() { iterator ret; ret.a_ = this; ret.pos_ = 0; return ret; }
  iterator end() { iterator ret; ret.a_ = this; ret.pos_ = num_integers_; 
    return ret; }
  Reference operator [] (uint64 i) { 
    return Reference(this, i); 
  }
  Reference GetRef(uint64 i);

};

int integerarray_main();

#endif
